home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1997 January / Macworld (1997-01).dmg / Games World / Shareware Games / Arcade / Mike's Breakout / Graphics.u < prev    next >
Text File  |  1996-10-11  |  14KB  |  480 lines

  1. {send all comments/gripes/etc to ani@atlas.nmsu.edu}
  2. {feel free to use this code for whatever you'd like.  i'd be grateful i helped make someone's day just a bit brighter}
  3. unit Graphics;
  4. interface
  5.     uses
  6.         TypeConst, MTGW;
  7.  
  8.     var    {explained when they are used}
  9.         NonMovingList: array[1..600] of Point;
  10.         NonMovingGrid: array[0..MAXGRIDX] of array[0..MAXGRIDY] of array[1..5] of ListGameObject;
  11.         CIcons: array[MINCICON..MAXCICON] of CIconHandle;
  12.         OffScreenWorld: GrafPtr;
  13.         TempOff: GWorldPtr;
  14.         NextDrawing: longint;
  15.         CurrentNonMoving, DeathCountdown, NumberRects: integer;
  16.         CopyRects: array[1..600] of Rect;
  17.         GridRect, VFlameRect, FlameRect, AllocatedRect: Rect;
  18.         BackPat: PixPatHandle;
  19.         StatusPat: PixPatHandle;
  20.         Window: WindowPtr;
  21.         StatusStart: Point;
  22.         TempBool: Boolean;
  23.         GWorldStart, ScreenStart: Ptr;
  24.         lives, Missiles, top, Score, GOffset, SOffset: longint;
  25.  
  26.     procedure XCopyBits (Where: Rect);
  27.     procedure DrawCopyRects;
  28.     function BiggestRect (First, Second: Rect): Rect;
  29.     procedure FlushLevelGraphics (WhatPixPat: integer);
  30.     procedure InitGraphics;
  31.     procedure Draw (var WhatOb: ListGameObject);
  32.     procedure DrawPaddle (var WhatOb: ListGameObject);
  33.     procedure DrawBrick (var WhatOb: ListGameObject);
  34.     procedure DrawBall (var WhatOb: ListGameObject);
  35.     procedure DrawMissile (var WhatOb: ListGameObject);
  36.     procedure DrawPaddlePiece (var WhatOb: ListGameObject);
  37.     procedure DrawPaddleExp (var WhatOb: ListGameObject);
  38.     procedure KABLAMMM (var WhatOb: ListGameObject);
  39.     procedure DrawDeadBrick (var WhatOb: ListGameObject);
  40.     procedure AddCopyRect (Where: Rect);
  41.     procedure FixErasure (FirstObject: ListGameObject);
  42.     procedure RestoreGraphics;
  43.     procedure CoordAndSize (var WhichRect: Rect; RLeft: integer; RTop: integer; RWidth: integer; RHeight: integer);
  44.     procedure DrawGridSquares;
  45.     procedure DrawGridSingleSquare (var Where: Point);
  46.     procedure DrawStatusBar;
  47.     procedure UpdateStatusBar;
  48.  
  49. implementation
  50.  
  51.     procedure CoordAndSize;
  52.     begin
  53.         with WhichRect do
  54.             begin
  55.                 top := RTop;
  56.                 left := RLeft;
  57.                 bottom := RTop + RHeight;
  58.                 right := RLeft + RWidth;
  59.             end;
  60.     end;        {this is just a macro to set a rect quickly}
  61.  
  62.     procedure AddCopyRect (Where: Rect);
  63.     begin
  64.         NumberRects := NumberRects + 1;
  65.         if NumberRects < 11 then
  66.             CopyRects[NumberRects] := Where;
  67.     end;        {add a new rect to be copied onto the screen}
  68.  
  69.     function BiggestRect;
  70.     begin
  71.         if Second.top < First.top then
  72.             AllocatedRect.top := Second.top
  73.         else
  74.             AllocatedRect.top := First.top;
  75.         if Second.left < First.left then
  76.             AllocatedRect.left := Second.left
  77.         else
  78.             AllocatedRect.left := First.left;
  79.         if Second.right > First.right then
  80.             AllocatedRect.right := Second.right
  81.         else
  82.             AllocatedRect.right := First.right;
  83.         if Second.bottom > First.bottom then
  84.             AllocatedRect.bottom := Second.bottom
  85.         else
  86.             AllocatedRect.bottom := First.bottom;
  87.         BiggestRect := AllocatedRect;
  88.     end;            {quite simply, find the smallest rect that can fit two larger ones}
  89.  
  90.     procedure DrawBrick;
  91.     begin
  92.         with WhatOb^ do
  93.             begin
  94.                 AddCopyRect(CurrentPlace);
  95.                 if DoDispose then
  96.                     EraseRect(CurrentPlace)
  97.                 else
  98.                     PlotCIcon(CurrentPlace, CIcons[frame]);
  99.             end;
  100.     end;
  101.  
  102.     procedure DrawBall;
  103.     begin
  104.         with WhatOb^ do
  105.             begin
  106.                 frame := frame + 1;
  107.                 if frame = 308 then
  108.                     frame := 300;
  109.                 PlotCIcon(CurrentPlace, CIcons[frame]);
  110.                 AddCopyRect(BiggestRect(LastPlace, CurrentPlace));
  111.                 LastPlace := CurrentPlace;
  112.             end;
  113.     end;        {draw the ball, go to the next frame}
  114.  
  115.     procedure DrawMissile;
  116.     begin
  117.         with WhatOb^ do
  118.             begin
  119.                 PlotCIcon(CurrentPlace, CIcons[600]);
  120.                 AddCopyRect(BiggestRect(LastPlace, CurrentPlace));
  121.                 if (A <= -8) then        {if we are going slow then draw the flame}
  122.                     begin
  123.                         CoordAndSize(AllocatedRect, CurrentPlace.left, CurrentPlace.bottom, VFlameRect.right, VFlameRect.bottom);
  124.                         PlotCIcon(AllocatedRect, CIcons[350 + E]);
  125.                         if (E = 2) then
  126.                             E := 0;
  127.                         E := E + 1;
  128.                     end;
  129.                 LastPlace := CurrentPlace;
  130.                 LastPlace.Bottom := LastPlace.Bottom + VFlameRect.bottom;
  131.             end;
  132.     end;        {draw the missle and its flame (where nessecary) }
  133.  
  134.     procedure DrawPaddle;    {this one is kind of complicated, eh?}
  135.         var
  136.             PaddleRect: Rect;
  137.     begin
  138.         with WhatOb^ do
  139.             begin
  140.                 PaddleRect := CurrentPlace;
  141.                 PaddleRect.right := PaddleRect.right + 40;
  142.                 PaddleRect.left := PaddleRect.left - 40;        {create a rect large enough to accomodate the flames}
  143.                 if E <> 0 then    {this is if the smacking trampoline is out}
  144.                     begin
  145.                         if E > 0 then
  146.                             PlotCIcon(ExtraRectA, CIcons[650]);
  147.                         PaddleRect.top := PaddleRect.top - 20;
  148.                         E := E - 1;                                        {plot it, enlarge copy/erase rect for it, and make its counter go down}
  149.                     end;
  150.                 PlotCIcon(CurrentPlace, CIcons[frame]);
  151. {PaddleRect := BiggestRect(CurrentPlace, LastPlace);}
  152.                 B := B + 1;
  153.                 if B = 3 then
  154.                     B := 0;
  155.                 case A of            {just draw the flame in the right direction}
  156.                     FLAMERIGHT: 
  157.                         begin
  158.                             CoordAndSize(AllocatedRect, CurrentPlace.right, CurrentPlace.top + 2, FlameRect.right, FlameRect.bottom);
  159.                             PlotCIcon(AllocatedRect, CIcons[700 + B]);
  160.                         end;
  161.                     FLAMELEFT: 
  162.                         begin
  163.                             CoordAndSize(AllocatedRect, CurrentPlace.left - FlameRect.right, CurrentPlace.top + 2, FlameRect.right, FlameRect.bottom);
  164.                             PlotCIcon(AllocatedRect, CIcons[750 + B]);
  165.                         end;
  166.                     otherwise
  167.                         ;
  168.                 end;
  169.                 LastPlace := PaddleRect;
  170.             end;
  171.         AddCopyRect(PaddleRect);
  172. {Draw the paddle depednding on where the object is}
  173.     end;
  174.  
  175.     procedure DrawPaddlePiece (var WhatOb: ListGameObject);
  176.     begin
  177.         with WhatOb^ do
  178.             begin
  179.                 if CurrentPlace.top > BOTTOMBOUNDRY then
  180.                     begin
  181.                         DeathCountdown := DeathCountdown + 1;
  182.                         DoDispose := TRUE;                {we went off the screen, let's go away}
  183.                     end
  184.                 else
  185.                     PlotCIcon(CurrentPlace, CIcons[frame + C]);
  186.                 AddCopyRect(BiggestRect(CurrentPlace, LastPlace));
  187.                 LastPlace := CurrentPlace;
  188.             end;
  189.     end;        {this simply draws a piece of the blown up paddle}
  190.  
  191.     procedure DrawPaddleExp (var WhatOb: ListGameObject);
  192.     begin
  193.         with WhatOb^ do
  194.             begin
  195.                 if frame = 912 then
  196.                     begin
  197.                         DoDispose := TRUE;
  198.                     end
  199.                 else
  200.                     begin
  201.                         frame := frame + 1;
  202.                         PlotCIcon(CurrentPlace, CIcons[frame]);
  203.                     end;
  204.                 AddCopyRect(LastPlace);
  205.             end;
  206.     end;        {draw the paddle's explosion (not the pieces)}
  207.  
  208.     procedure DrawDeadBrick;
  209.     begin
  210.         with WhatOb^ do
  211.             begin
  212.                 PlotCIcon(CurrentPlace, CIcons[frame]);
  213.                 if frame <> 1114 then
  214.                     frame := frame + 1
  215.                 else
  216.                     begin
  217.                         EraseRect(LastPlace);
  218.                         DoDispose := TRUE;
  219.                     end;
  220.                 AddCopyRect(LastPlace);
  221.             end;
  222.     end;            {this is not used, because my machine was too slow to handle it, but you can put it back in,}
  223.                 {in the grid collision section}
  224.  
  225.     procedure KABLAMMM;
  226.     begin
  227.         with WhatOb^ do
  228.             begin
  229.                 if frame = 412 then
  230.                     begin
  231.                         DoDispose := TRUE;
  232.                     end
  233.                 else
  234.                     begin
  235.                         frame := frame + 1;
  236.                         PlotCIcon(CurrentPlace, CIcons[frame]);
  237.                         OffsetRect(CurrentPlace, 20, 0);
  238.                         PlotCIcon(CurrentPlace, CIcons[frame]);
  239.                         OffsetRect(CurrentPlace, -10, 10);
  240.                         PlotCIcon(CurrentPlace, CIcons[frame]);
  241.                         OffsetRect(CurrentPlace, -10, -10);
  242.                     end;
  243.                 AddCopyRect(LastPlace);
  244.             end;
  245.     end;        {create the tri-iconed flame.  mike wanted the cute function name}
  246.  
  247.     procedure Draw;
  248.     begin
  249.         if (WhatOb^.ID <> 0) then
  250.             begin
  251.                 case WhatOb^.ID of
  252.                     PADDLE: 
  253.                         begin
  254.                             DrawPaddle(WhatOb);
  255.                         end;
  256.                     MISSILE: 
  257.                         begin
  258. {UpdateNonMovingGrid(WhatOb);}
  259.                             DrawMissile(WhatOb);
  260.  {Warning: this may be a must-have later}
  261.                         end;
  262.                     BALL: 
  263.                         begin
  264. {UpdateNonMovingGrid(WhatOb);}
  265.                             DrawBall(WhatOb);
  266.                         end;
  267.                     EXPLOSION: 
  268.                         begin
  269.                             KABLAMMM(WhatOb);
  270.                         end;
  271.                     BRICK: 
  272.                         begin
  273.                             DrawBrick(WhatOb);
  274.                         end;
  275.                     DEADBRICK: 
  276.                         begin
  277.                             DrawDeadBrick(WhatOb);
  278.                         end;
  279.                     PADDLEPIECE: 
  280.                         DrawPaddlePiece(WhatOb);
  281.                     PADDLEEXP: 
  282.                         DrawPaddleExp(WhatOb);
  283.                 end;
  284.                 if WhatOb^.DoDispose = TRUE then
  285.                     begin
  286.                         EraseRect(WhatOb^.LastPlace);
  287.                         AddCopyRect(WhatOb^.LastPlace);        {if the object needs to go away just erase it}
  288.                     end;
  289.             end;
  290.     end;        {this picks what function to use depending on the object's type.  yes, this}
  291.             {would be better with function pointers}
  292.  
  293.     procedure UpdateStatusBar;
  294.         var
  295.             ErasingRect: Rect;
  296.             CurrStr: Str255;
  297.     begin
  298.         BackPixPat(StatusPat);
  299.         CoordAndSize(ErasingRect, StatusStart.h, StatusStart.v, RIGHTBOUNDRY, 30);
  300.         MoveTo(StatusStart.h, StatusStart.v + 2);
  301.         PenSize(3, 3);
  302.         Line(RIGHTBOUNDRY, 0);
  303.         PenSize(1, 1);
  304.         EraseRect(ErasingRect);
  305.         ForeColor(BlackColor);
  306.         MoveTo(StatusStart.h, StatusStart.v + 16);
  307.         TextSize(16);
  308.         CurrStr := StringOf('Score: ', score : 10);
  309.         DrawString(CurrStr);
  310.         MoveTo(StatusStart.h + 175, StatusStart.v + 16);
  311.         CurrStr := StringOf('Missiles: ', missiles : 10);
  312.         DrawString(CurrStr);
  313.         MoveTo(StatusStart.h + 375, StatusStart.v + 16);
  314.         CurrStr := StringOf('Lives: ', lives : 10);
  315.         DrawString(CurrStr);
  316.         TextSize(10);
  317.         MoveTo(5, 326);
  318.         CurrStr := StringOf('Top Score: ', top : 10);
  319.         DrawString(CurrStr);
  320.         BackPixPat(BackPat);
  321.         AddCopyRect(ErasingRect);
  322.     end;            {ok, this may be a bit of code, but it's really simple; it just draws all yer info}
  323.  
  324.     procedure DrawStatusBar;
  325.         var
  326.             ErasingRect: Rect;
  327.     begin
  328.         BackPixPat(StatusPat);
  329.         CoordAndSize(ErasingRect, StatusStart.h, StatusStart.v, RIGHTBOUNDRY, 30);
  330.         EraseRect(ErasingRect);
  331.         MoveTo(StatusStart.h, StatusStart.v);
  332.         PenSize(3, 3);
  333.         Line(RIGHTBOUNDRY, 0);
  334.         PenSize(1, 1);
  335.         UpdateStatusBar;
  336.     end;        {this erases the place where the status bar goes, i think i remember this is silly for some reason,}
  337.             {you can probably figure it out}
  338.  
  339.     procedure FlushLevelGraphics;
  340.     begin
  341.         CurrentNonMoving := 0;
  342.         SetGWorld(GWorldPtr(OffScreenWorld), nil);
  343.         DisposePixPat(BackPat);
  344.         BackPat := GetPixPat(WhatPixPat);
  345.         BackPixPat(BackPat);
  346.         EraseRect(Window^.PortRect);
  347.         NumberRects := 0;
  348.         DrawStatusBar;
  349.         SetGWorld(GWorldPtr(Window), GetMainDevice);    {go to the window}
  350. {    XCopyBits(Window^.PortRect);  (don't ask)}
  351. {CopyBits(OffScreenWorld^.PortBits, Window^.PortBits, Window^.PortRect, Window^.PortRect, srcCopy, nil);}
  352.         NextDrawing := TickCount + 5;                        {this is so the fps remains constant}
  353.         SetGWorld(GWorldPtr(OffScreenWorld), nil);        {go back to the offscreen world}
  354.     end;         {Just clear the screen for the next level , right ?    }
  355.  
  356.     procedure XCopyBits (Where: Rect);
  357.         var
  358.             XAmt, YAmt: integer;
  359.             ByteG, ByteS, GRow, SRow: Ptr;
  360.     begin
  361.         ByteG := GWorldStart;
  362.         ByteS := ScreenStart;
  363.         GRow := ByteG;
  364.         SRow := ByteS;
  365.         for YAmt := 0 to 470 do
  366.             begin
  367.                 for XAmt := 0 to 630 do
  368.                     begin
  369.                         ByteS^ := ByteG^;
  370.                         ByteG := Ptr(Ord4(ByteG) + 1);
  371.                         ByteS := Ptr(Ord4(ByteS) + 1);
  372.                     end;
  373.                 GRow := Ptr(Ord4(GRow) + GOffset);
  374.                 SRow := Ptr(Ord4(SRow) + SOffset);
  375.                 ByteS := SRow;
  376.                 ByteG := GRow;
  377. {    ByteG := Ptr(Ord4(ByteG) + Offset - 200);}
  378. {    ByteS := Ptr(Ord4(ByteS) + Offset - 200);}
  379.             end;
  380.         while not button do
  381.             ;
  382.     end;        {this is my retarded attempt at a blitter... at least i tried, right?}
  383.  
  384.     procedure DrawCopyRects;
  385.         var
  386.             i: integer;
  387.             CurrRect: Rect;
  388.     begin
  389.         UpdateStatusBar;
  390.         SetGWorld(GWorldPtr(Window), GetMainDevice);
  391.         if NumberRects > 3 then
  392.             begin
  393.             end;
  394. {Wait for next tick}
  395.         while TickCount < NextDrawing do
  396.             ;
  397.         if NumberRects < 10 then
  398.             begin
  399.                 for i := 1 to NumberRects do
  400.                     begin
  401.                         CurrRect := CopyRects[i];
  402.                         CopyBits(OffScreenWorld^.PortBits, Window^.PortBits, CurrRect, CurrRect, srcCopy, nil);
  403.                     end;
  404.             end
  405.         else
  406.             CopyBits(OffScreenWorld^.PortBits, Window^.PortBits, Window^.PortRect, Window^.PortRect, srcCopy, nil);
  407.         NextDrawing := TickCount + 3;  {fps}
  408.         NumberRects := 0;
  409.         SetGWorld(GWorldPtr(OffScreenWorld), nil);
  410.     end;        {draw each rect that needs to be copied (is dirty, they say), and if there's too many just do the whole screen}
  411.  
  412.     procedure RestoreGraphics;
  413.     begin
  414.         SetGWorld(GWorldPtr(Window), GetMainDevice);
  415.     end;    {this _could_ do more, but right now it just does the obvious, set the screen back to the window}
  416.  
  417.     procedure FixErasure;
  418.         var
  419.             CurrentObject: ListGameObject;
  420.     begin
  421.         CurrentObject := FirstObject;
  422.         while (CurrentObject <> nil) do
  423.             begin
  424.                 if CurrentObject^.ID <> 0 then
  425.                     EraseRect(CurrentObject^.LastPlace);
  426.                 CurrentObject := CurrentObject^.Next;
  427.             end;
  428.     end;        { Erase all sprites so we can draw em all over again ( whee )}
  429.  
  430.     procedure DrawGridSingleSquare;
  431.         var
  432.             k: integer;
  433.             UpdatePlace: Rect;
  434.     begin
  435.         for k := 1 to 5 do
  436.             if NonMovingGrid[Where.h, Where.v, k] <> nil then
  437.                 Draw(NonMovingGrid[Where.h, Where.v, k]);
  438.     end;        {if there's stuff in any of the grid objects, then draw it, eh}
  439.  
  440.     procedure DrawGridSquares;
  441.     begin
  442.         if (CurrentNonMoving = 0) then
  443.             Exit(DrawGridSquares);
  444.         while CurrentNonMoving <> 0 do
  445.             begin
  446.                 DrawGridSingleSquare(NonMovingList[CurrentNonMoving]);
  447.                 CurrentNonMoving := CurrentNonMoving - 1;
  448.             end;
  449.         CurrentNonMoving := 0;
  450.     end;        {call each square to draw, only draw what we need to with the currentnonmoving counter}
  451.  
  452.     procedure InitGraphics;
  453.         var
  454.             i: integer;
  455.     begin
  456.         randSeed := TickCount;
  457.         Window := GetNewCWindow(128, nil, WindowPtr(-1));
  458.         SetPort(Window);
  459.         if noErr <> NewGWorld(GWorldPtr(OffScreenWorld), 0, Window^.PortRect, nil, nil, [pixelsLocked]) then
  460.             ; {Hope not to crash}
  461.         if LockPixels(CGrafPtr(OffScreenWorld)^.PortPixMap) then
  462.             ; {Hope not to crash}
  463.         GWorldStart := GetPixBaseAddr(GWorldPtr(OffScreenWorld)^.PortPixMap);
  464.         ScreenStart := GetPixBaseAddr(GWorldPtr(Window)^.PortPixMap);
  465.         TempOff := GWorldPtr(Window);
  466.         SOffset := BitAnd(GetGWorldPixMap(TempOff)^^.rowBytes, $3FFF);
  467.         TempOff := GWorldPtr(OffScreenWorld);
  468.         GOffset := BitAnd(GetGWorldPixMap(TempOff)^^.rowBytes, $3FFF);
  469.         SetGWorld(GWorldPtr(OffScreenWorld), nil);
  470.  
  471.         for i := MINCICON to MAXCICON do
  472.             CIcons[i] := GetCIcon(i);
  473.         FlameRect := CIcons[700]^^.iconpmap.bounds;
  474.         VFlameRect := CIcons[350]^^.iconpmap.bounds;
  475.         SetRect(GridRect, 0, 0, BLOCKSIZE, BLOCKSIZE);
  476.         StatusPat := GetPixPat(130);
  477.         StatusStart.h := 0;
  478.         StatusStart.v := 300;
  479.     end;        {this silly function does some really simple init stuff, plus it loads each cicon}
  480. end.